#ifndef __MY_DATA__
#define __MY_DATA__

#include "tool.hpp"
#include "Config.hpp"
#include <pthread.h>
#include <unordered_map>




namespace Cloud_up
{
    //文件信息
    struct BackupInfo
    {
        bool _pack_flag;        // 热点状态
        time_t _mtime;          // 最后修改时间
        time_t _atime;          // 最后访问时间
        size_t _fsize;          // 文件大小
        std::string _real_path; // 文件实际存储路径
        std::string _url_path;  // 浏览器下载资源路径 前缀
        std::string _pack_path; // 文件压缩包存储路径

        bool NewBackupInfo(const std::string &realpath) //新建一个文件信息
        {
            Filetool ft(realpath);
            if (ft.Exists() == false)
            {
                std::cout << "Exists faile" << std::endl;
                return false;
            }

            Config *cf = Cloud_up::Config::GetInstance(); //实例懒汉
            if (cf->ReadConfig() != true) //读配置
            {
                return false;
            }

            std::string packdir = cf->GetPackDir(); // 压缩包路径
            // std::cout<<packdir<<std::endl;

            std::string packsuffix = cf->GetArcSuffix(); // 压缩包后缀
            // std::cout<<packsuffix<<std::endl;

            std::string url = cf->GetUrlPrefix(); // 下载路径
            // std::cout<<url<<std::endl;

            this->_pack_flag = false;
            this->_mtime = ft.LastMTime();
            this->_atime = ft.LastATime();
            this->_fsize = ft.File_size();

            this->_real_path = realpath;
            // std::cout<<_real_path<<std::endl;
            // ./back_dir/1.doc   -> ./back_dir/1.doc.lz
            this->_pack_path = packdir + ft.FileName() + packsuffix;
            // std::cout<<_pack_path<<std::endl;

            
            // ./back_dir/1.doc   -> ./url/1.doc
            this->_url_path = url + ft.FileName();
            // std::cout<<_url_path<<std::endl;


            return true;
        }
    };
    //数据信息

    class DataManager
    {
    private:
        std::string _backup_file; // 持久化数据文件
        pthread_rwlock_t _rwlock; // 读写锁 读共享，写互斥
        std::unordered_map<std::string, BackupInfo> _table;

    public:
        DataManager()
        {
            _backup_file = Config::GetInstance()->GetManagerFile(); //获取文件存储信息
            pthread_rwlock_init(&_rwlock, NULL);//初始化锁
            InitLoad(); //加载
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&_rwlock);
        }

        bool InitLoad() // 初始化程序运行时从文件读取数据
        {
            // 1.判断文件是否存在
            // 2.获取数据
            // 3.反序列化
            Filetool ft(_backup_file);
            if (ft.Exists() == false)
            {
                std::cout << "文件不存在" << std::endl;
                return false;
            }

            std::string str;
            ft.GetContent(&str);

            Json::Value val;
            json_tool::UnSerialize(str, &val);

            for (int i = 0; i < val.size(); i++)
            {
                BackupInfo info;
                info._pack_flag = val[i]["_pack_flag"].asInt();
                info._atime = val[i]["_atime"].asInt64();
                info._mtime = val[i]["_mtime"].asInt64();
                info._fsize = val[i]["_fsize"].asInt64();
                info._pack_path = val[i]["_pack_path"].asString();
                info._real_path = val[i]["_real_path"].asString();
                info._url_path = val[i]["_url_path"].asString();
                Insert(info);
            }
            return true;
        }
        bool Storage() // 每次有信息改变则需要持久化存储一次
        {
            // 获取数据
            std::vector<BackupInfo> arry;
            this->GetAll(&arry);

            // 获取json文件
            Json::Value root;
            //更新back.dat的数据
            for (int i = 0; i < _table.size(); i++)
            {
                Json::Value val;
                val["_pack_flag"] = arry[i]._pack_flag;
                val["_mtime"] = (Json::Int64)arry[i]._mtime;
                val["_atime"] = (Json::Int64)arry[i]._atime;
                val["_fsize"] = (Json::Int64)arry[i]._fsize;
                val["_real_path"] = arry[i]._real_path;
                val["_url_path"] = arry[i]._url_path;
                val["_pack_path"] = arry[i]._pack_path;
                root.append(val);
            }
            // std::cout<<root<<std::endl;
            // 数据序列化
            std::string str;
            json_tool::Serialize(root, &str);
            // std::cout << _backup_file << std::endl;

            // 写进back.dat文件
            Filetool ft(_backup_file);
            ft.SetContent(str);
            return true;
        }

        bool Insert(const BackupInfo &val) // 新增
        {
            pthread_rwlock_wrlock(&_rwlock);//读共享写互斥
            _table[val._url_path] = val; //存放文件信息到浏览器路径中
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }
        bool Update(const BackupInfo &val) // 修改
        {
            pthread_rwlock_wrlock(&_rwlock);
            _table[val._url_path] = val;
            pthread_rwlock_unlock(&_rwlock);
            Storage();
            return true;
        }

        bool GetOneByURL(const std::string &url, BackupInfo *val) // 获取唯一标识
        {
            // 搜索是否有对应的url 有的话就更新所有信息
            pthread_rwlock_wrlock(&_rwlock);
            for (auto it = _table.begin(); it != _table.end(); it++)
            {
                if (it->second._url_path == url)
                {
                    *val = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
        }

        // pthread_rwlock_wrlock(&_rwlock);
        // auto it = _table.find(url);
        // if(it == _table.end())
        // {
        //     pthread_rwlock_unlock(&_rwlock);
        //     return false;
        // }

        // *val = it->second;
        // pthread_rwlock_unlock(&_rwlock);
        // return true;
        // }

        bool GetOneByRealPath(const std::string &realpath, BackupInfo *val) // 获取唯一文件实际存储路径
        {
            // 判断是文件实际路径是否存在，存在就更新信息
            pthread_rwlock_wrlock(&_rwlock);
            for (auto it = _table.begin(); it != _table.end(); it++)
            {
                if (it->second._real_path == realpath)
                {
                    *val = it->second;
                    pthread_rwlock_unlock(&_rwlock);
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock);
            return false;
        }

        bool GetAll(std::vector<BackupInfo> *arry) // 获取所有
        {
            pthread_rwlock_wrlock(&_rwlock);
            // 获取所有backinfo 存到数组里 
            for (auto it = _table.begin(); it != _table.end(); it++) 
            {
                arry->push_back(it->second);
            }
            pthread_rwlock_unlock(&_rwlock);
            return true;
        }
    };
}
#endif
